//
// Created by pzw on 24-3-22.
//

#include "FuncAdapter.h"

/**
 * 这样写返回值，需要使用函数时，指明所有模板参数；
 * @tparam Func - 函数
 * @tparam Args - Func函数的参数
 * @param func  - Func函数实例
 * @param args  - Func函数实参
 * @return Ret  - 返回值类型实例
 */
template<typename Func, typename Ret, typename... Args>
Ret FuncAdapter::std_func_bind(Func &&func, Args &&... args) {
    auto bind = std::bind(func, args...);
    Ret ret = bind();
    return ret;
}

/**
 * 这样写(typename std::result_of<Func(Args...)>::type)返回值，可以不用使用函数时，指明所有模板参数；
 * @tparam Func - 函数
 * @tparam Args - Func函数的参数
 * @param func  - Func函数实例
 * @param args  - Func函数实参
 * @return typename std::result_of<Func(Args...)>::type - 萃取这个函数，调用参数后的返回值类型
 */
template<typename Func, typename... Args>
typename std::result_of<Func(Args...)>::type FuncAdapter::std_func_bind2(Func &&func, Args &&... args) {
    auto bind = std::bind(std::forward<Func>(func), std::forward<Args>(args)...);
    return bind();
}

void FuncAdapter::std_ref() {
    using namespace std;
    int (*incr)(int &) = [](int &a) -> int {
        return ++a;
    };
    int i = 0;
    incr(i);
    cout << "std_ref: incr(i) = " << i << endl;
    auto inc = bind(incr, 1);
    inc(ref(i));
    cout << "std_ref: inc(ref(i)) = " << i << endl;
}

void FuncAdapter::std_ref2() {
    using namespace std;
    int (*incr)(int &) = [](int &a) -> int {
        return (++a);
    };
    int i = 1;
    incr(i);
    cout << "std_ref2: incr(i) = " << i << endl;
    auto inc = bind(incr, 1);
    inc(cref(i));
    cout << "std_ref2: inc(cref(i)) = " << i << endl;
}

template<typename Func, typename Class, typename ...Args>
typename std::result_of<Func(Class *, Args...)>::type FuncAdapter::std_mem_fn(
        Class *classptr,
        Func func,
        Args ...args
) {
    using namespace std;
    auto mem_func = mem_fn(func);
    return mem_func(classptr, args...);
}

template<typename Tp, typename Class>
std::_Mem_fn<Tp Class::*> FuncAdapter::std_mem_fn2(Tp Class::* pm) noexcept {
    using namespace std;
    auto mem_func = mem_fn(pm);
    return mem_func;
}

/**
 * 这里的{Tp Class::*}语法，是表示一个类的成员的指针：
 * 1. 如果这个成员是成员变量，那么这个Tp就是Class的这个成员变量的变量类型；
 * 2. 如果这个成员是成员函数，那么这个Tp就是Class的这个成员函数的返回值类型；
 *
 * @tparam Tp     - Class成员变量的类型或者成员函数的返回值类型
 * @tparam Class  - Class
 * @param pm      - Tp Class::* pm的指针
 * @return        - std::_Mem_fn<Tp Class::*>标准库api
 */
template<typename Tp, typename Class>
std::_Mem_fn<Tp Class::*> FuncAdapter::std_mem_fn3(Tp Class::* pm) noexcept {
    using namespace std;
    auto fn = mem_fn(pm);
    return fn;
}

void FuncAdapter::std_func() {
    using namespace std;
    fn = std_round;
    cout << "std_func: std_round->fn(7.6) = " << fn(7.6) << endl;

    fn = Round(Round_style::truncate);
    cout << "std_func: Round->fn(7.6) = " << fn(7.6) << endl;

    Round_style style = Round_style::round;
    fn = [style](double x) -> int {
        return style == Round_style::round ? (x + 0.5) : (x);
    };
    cout << "std_func: lambda->fn(7.6) = " << fn(7.6) << endl;

    vector<double> v{7.6};
    fn = Round(Round_style::round);
    transform(v.begin(), v.end(), v.begin(), fn);
    cout << "std_func: transform->fn(7.6)->v[0] = " << v[0] << endl;
}

int FuncAdapter_main() {
    using namespace std;
    bool (*compare)(int, int) = [](int a, int b) -> bool {
        return a < b;
    };
    bool smaller = FuncAdapter::std_func_bind<function<bool(int, int)>, bool, int, int>(compare, 1, 2);
    bool smaller2 = FuncAdapter::std_func_bind2(compare, 1, 2);
    cout << "FuncAdapter_main: std_func_bind, smaller = " << smaller << endl;
    cout << "FuncAdapter_main: std_func_bind, smaller2 = " << smaller2 << endl;

    FuncAdapter::std_ref();
    FuncAdapter::std_ref2();

    Shape *pShape = new Shape();
    int (Shape::* draw2)(float) = &Shape::draw2;
    const int &ret = FuncAdapter::std_mem_fn(pShape, draw2, 10.0f);
    cout << "FuncAdapter_main: std_mem_fn, ret = " << ret << endl;

    auto mem_fn2 = mem_fn(&Shape::draw2);
    mem_fn2(pShape, 100.0f);

#if 1
    Shape *pShape2 = new Shape();
    int (Shape::* draw23)(float) = &Shape::draw2;
    auto mem_fn22 = FuncAdapter::std_mem_fn2(draw23);
    const int &ret22 = mem_fn22(pShape2, 10.0f);
    cout << "FuncAdapter_main: std_mem_fn2, ret22 = " << ret22 << endl;
#endif
    Shape *pShape3 = new Shape();
    const _Mem_fn<int (Shape::*)(float)> &fn = FuncAdapter::std_mem_fn3(&Shape::draw2);
    const std::_Mem_fn<float Shape::*> &fn2 = FuncAdapter::std_mem_fn3(&Shape::radian);
    auto ret3 = fn(pShape3, 10.f);
    auto ret32 = fn2(pShape3);
    cout << "FuncAdapter_main: std_mem_fn3, ret3 = " << ret3 << ", ret32 = " << ret32 << endl;

    FuncAdapter::std_func();

    return 0;
}
